Skip to content

SAML2: support service provider certificate overlap rotation#1453

Open
mbardelmeijer wants to merge 2 commits into
SocialiteProviders:masterfrom
mbardelmeijer:feature/saml2-sp-certificate-soft-swap
Open

SAML2: support service provider certificate overlap rotation#1453
mbardelmeijer wants to merge 2 commits into
SocialiteProviders:masterfrom
mbardelmeijer:feature/saml2-sp-certificate-soft-swap

Conversation

@mbardelmeijer

@mbardelmeijer mbardelmeijer commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Why this is needed

When a Laravel application acts as a SAML service provider with signed AuthnRequest messages, identity providers must trust the SP's signing certificate ("request signer certificate"). Many IdPs — especially enterprise and government setups — register that certificate once and pin it, rather than continuously refreshing SP metadata.

Today this package only supports a single sp_certificate / sp_private_key pair. Replacing those values is therefore a hard cutover: metadata and outbound signatures switch to the new key immediately, while IdPs that still trust only the old certificate reject login requests until an administrator manually updates their configuration.

That is a problem in normal operations, not just at initial setup:

  • SP signing certificates expire and must be rotated on a schedule (often every 1–3 years).
  • Compliance requirements may mandate shorter lifetimes or replacement of non-conforming certificates.
  • Operators need a grace period so customers can update pinned certificates without an SSO outage.

The package already handles the inbound side of this well: when an IdP publishes multiple signing certificates in metadata, validateSignature() accepts any of them. There is no equivalent for the outbound SP signing certificate, which is what this PR adds.

What this changes

Adds optional overlap credentials via three new config keys:

  • sp_previous_certificate
  • sp_previous_private_key
  • sp_previous_private_key_passphrase

During a rotation overlap period, operators deploy the new active sp_* credentials and keep the replaced pair in sp_previous_* for a grace window (typically 30–90 days).

Metadata publication: SP metadata includes KeyDescriptor entries for both the active and previous certificates (signing and encryption).

Outbound signing: AuthnRequest, LogoutRequest, and LogoutResponse messages are signed with the active key only. The entity descriptor signature also uses the active key.

Inbound decryption: If assertions are encrypted, decryption is attempted with the active private key first, then the previous private key.

Application API: Adds getServiceProviderCertificates() so applications can expose all currently published SP certificates (for example on a /certificate endpoint) without parsing metadata XML.

credential() is preserved as an alias to the active signing credential, so existing behaviour is unchanged when sp_previous_* is not configured.

Recommended rotation workflow

  1. Generate and deploy a new active sp_certificate / sp_private_key.
  2. Move the replaced certificate and private key to sp_previous_*.
  3. Notify IdP administrators to refresh SP metadata or update their pinned request-signer certificate.
  4. After the grace period, remove sp_previous_*.

Documentation for this workflow is added to the SAML2 README.

Allow optional sp_previous_* credentials so metadata can publish both
active and previous signing certificates during a soft-swap, while
outbound messages are signed with the active key and encrypted
assertions can be decrypted with either key.
Keep the PR limited to Provider logic and README documentation.
@mbardelmeijer

Copy link
Copy Markdown
Contributor Author

@27pchrisl if you're able to take a look at this, that would be great! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant